package com.fastbee.sip.server;

import com.fastbee.sip.domain.SipConfig;
import com.fastbee.sip.domain.SipDevice;
import com.fastbee.sip.model.VideoSessionInfo;
import com.fastbee.sip.service.ISipCacheService;
import com.fastbee.sip.service.ISipConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.ArrayList;

@Component
public class ReqMsgHeaderBuilder {
    @Autowired
    private SipFactory sipFactory;

    @Autowired
    @Qualifier(value = "udpSipServer")
    private SipProvider sipserver;

    @Autowired
    private VideoSessionManager streamSession;

    @Autowired
    private ISipConfigService sipConfigService;

    @Autowired
    @Qualifier(value = "udpSipServer")
    private SipProvider udpSipServer;

    @Autowired
    private ISipCacheService sipCacheService;


    /**
     * 创建请求消息
     *
     * @param device
     * @param content
     * @param viaTag
     * @param fromTag
     * @param toTag
     * @return
     * @throws ParseException
     * @throws InvalidArgumentException
     * @throws PeerUnavailableException
     */
    public Request createMessageRequest(SipDevice device, String content, String viaTag, String fromTag, String toTag)
            throws ParseException, InvalidArgumentException, PeerUnavailableException {

        Request request = null;

        SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
        if (sipConfig != null) {
            // sipuri
            SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceSipId(),
                    device.getHostaddress());
            // via
            ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
            ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(),
                    sipConfig.getPort(), device.getTransport(), viaTag);
            viaHeader.setRPort();
            viaHeaders.add(viaHeader);
            // from
            SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
                    sipConfig.getIp() + ":" + sipConfig.getPort());
            Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
            FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
            // to
            SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceSipId(),
                    sipConfig.getDomain());
            Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
            ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
            // callid
            CallIdHeader callIdHeader = sipserver.getNewCallId();
            // Forwards
            MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
            // ceq
            CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);

            request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader,
                    fromHeader, toHeader, viaHeaders, maxForwards);
            ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
                    "MANSCDP+xml");
            request.setContent(content, contentTypeHeader);
        }
        return request;
    }

    public Request createInviteRequest(SipDevice device, String channelId, String content, String viaTag, String fromTag,
                                       String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
        Request request = null;
        // 请求行
        SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
        // via
        ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
        ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
                device.getTransport(), viaTag);
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);

        SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
        if (sipConfig != null) {
            // from
            SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
                    sipConfig.getDomain());
            Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
            FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); // 必须要有标记，否则无法创建会话，无法回应ack
            // to
            SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getDomain());
            Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
            ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);

            // callid
            CallIdHeader callIdHeader = sipserver.getNewCallId();

            // Forwards
            MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);

            // ceq
            CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
            request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,
                    fromHeader, toHeader, viaHeaders, maxForwards);

            Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
                    .createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));

            request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
            // Subject
            SubjectHeader subjectHeader = sipFactory.createHeaderFactory()
                    .createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getIp(), 0));
            request.addHeader(subjectHeader);
            ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
                    "SDP");
            request.setContent(content, contentTypeHeader);
        }
        return request;
    }

    public Request createPlaybackInviteRequest(SipDevice device, String channelId, String content, String viaTag,
                                               String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
        Request request = null;

        SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
        if (sipConfig != null) {
            // 请求行
            SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId,
                    device.getHostaddress());
            // via
            ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
            ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
                    device.getTransport(), viaTag);
            viaHeader.setRPort();
            viaHeaders.add(viaHeader);
            // from
            SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
                    sipConfig.getDomain());
            Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
            FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); // 必须要有标记，否则无法创建会话，无法回应ack
            // to
            SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
            Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
            ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);

            // callid
            CallIdHeader callIdHeader = sipserver.getNewCallId();

            // Forwards
            MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);

            // ceq
            CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
            request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,
                    fromHeader, toHeader, viaHeaders, maxForwards);

            Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
                    .createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));

            request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));

            ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
                    "SDP");
            request.setContent(content, contentTypeHeader);
        }
        return request;
    }


    public Request createRtspRequest(SipDevice device, String channelId, String streamId, String content)
            throws PeerUnavailableException, ParseException, InvalidArgumentException {

        Request request = null;
        VideoSessionInfo info = streamSession.get(streamId);
        Dialog dialog = info.getTransaction().getDialog();

        SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
        if (sipConfig != null) {
            // 请求行
            SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
            // via
            ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
            ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(getLocalIp(sipConfig.getIp()), sipConfig.getPort(),
                    device.getTransport(), info.getViaTag());
            viaHeader.setRPort();
            viaHeaders.add(viaHeader);
            // from
            SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
                    sipConfig.getDomain());
            Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
            FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, info.getFromTag());
            // to
            SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
            Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
            ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, dialog.getRemoteTag());
            // callid
            CallIdHeader callIdHeader = info.getCallId();
            // Forwards
            MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
            // ceq
            CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.INFO);

            request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,
                    fromHeader, toHeader, viaHeaders, maxForwards);

            Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
                    .createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));
            request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));

            ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
                    "MANSRTSP");
            request.setContent(content, contentTypeHeader);
        }
        return request;
    }

    public String getLocalIp(String deviceLocalIp) {
        if (!ObjectUtils.isEmpty(deviceLocalIp)) {
            return deviceLocalIp;
        }
        return udpSipServer.getListeningPoint().getIPAddress();
    }
}
